﻿using Microsoft.AspNetCore.Mvc;
using RabbitMQ.Client;
using System.Text;
using WAU.Library.RabbitMQ;
using WAU.Utilities;
using RabbitMQChannel = RabbitMQ.Client.IModel;

namespace WAU.Controllers
{
    /// <summary>
    /// 消息队列 controller，用于测试 RabbitMQ 相关内容
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class MQController : ControllerBase
    {
        private const string ROUTE_KEY = "test_routekey";
        private const string EXCHANGE_NAME = "test_exchange";
        private const string QUEUE_NAME = "test_queue";

        private readonly RabbitMQChannel _channel;

        /// <summary>
        /// ctor
        /// </summary>
        public MQController(ScopedRabbitMQModelLease rabbitMQConnectionLease)
        {
            _channel = rabbitMQConnectionLease.Channel;
        }

        /// <summary>
        /// 发送到消息队列基本功能
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult RabbitMQPublishTest(string msg = "MY_EMPTY")
        {
            msg = msg + " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff");

            // 声明交换机（如果没有则自动创建）
            //_channel.ExchangeDeclare(EXCHANGE_NAME, ExchangeType.Topic, true, false);

            byte[] body = Encoding.UTF8.GetBytes(msg);
            _channel.BasicPublish(EXCHANGE_NAME, ROUTE_KEY, null, body);

            return Ok(new Result
            {
                Success = true,
                Msg = $"已发送消息 {msg}"
            });
        }

        /// <summary>
        /// 发送到消息队列（生产者确认）
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult RabbitMQPublishConfirmTest(string msg = "MY_EMPTY")
        {
            var factory = RabbitMQService.ConnectionFactory;
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                channel.ConfirmSelect();

                // 声明交换机（如果没有则自动创建）
                channel.ExchangeDeclare(EXCHANGE_NAME, ExchangeType.Topic, true, false);

                byte[] body = Encoding.UTF8.GetBytes(msg);
                channel.BasicPublish(EXCHANGE_NAME, ROUTE_KEY, null, body);
                
                // 同步等待确认消息，如果服务器超时未确认 或 确认失败 则抛出异常
                channel.WaitForConfirmsOrDie(TimeSpan.FromSeconds(3));
                Console.WriteLine("消息发送成功");
            }

            return Ok(new Result
            {
                Success = true,
                Msg = $"已发送消息 {msg}"
            });
        }

        /// <summary>
        /// 发送到消息队列（发送到未绑定队列的交换机，接受 Publish Return 消息）
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult RabbitMQPublishReturnTest(string msg = "MY_EMPTY")
        {
            var factory = RabbitMQService.ConnectionFactory;
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                // 开启 Publish Confirm
                channel.ConfirmSelect();

                string exchangeName = EXCHANGE_NAME + "1";

                channel.ExchangeDeclare(exchangeName, ExchangeType.Topic, true, false);

                byte[] body = Encoding.UTF8.GetBytes(msg);

                // 接收 Publish Return 消息（当交换机存在，但没有匹配的路由时会触发）
                channel.BasicReturn += (obj, ea) =>
                {
                    Console.WriteLine(ea);
                };

                // 此时必须要设置 mandotary 为 true，告知 rabbitmq 如果无法路由到任何一个队列，则 BasicReturn 通知当前客户端
                channel.BasicPublish(exchangeName, ROUTE_KEY, true, null, body);

                // 交换机不存在时，直接报错
                channel.WaitForConfirms();
            }

            return Ok(new Result
            {
                Success = true,
                Msg = $"已发送消息 {msg}"
            });
        }

        /// <summary>
        /// 发送到消息队列（批量发送，批量确认）
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult RabbitMQBatchPublishConfirm(string msg = "MY_EMPTY")
        {
            var factory = RabbitMQService.ConnectionFactory;
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                channel.ConfirmSelect();

                // 声明交换机（如果没有则自动创建）
                channel.ExchangeDeclare(EXCHANGE_NAME, ExchangeType.Topic, true, false);

                // Ack 事件
                channel.BasicAcks += (obj, ea) =>
                {
                    Console.WriteLine(ea);
                };

                // Ack 事件
                channel.BasicNacks += (obj, ea) =>
                {
                    Console.WriteLine(ea);
                };

                IBasicPublishBatch ibpb = channel.CreateBasicPublishBatch();
                string[] msgs = msg.Split(",");

                foreach (string m in msgs) 
                {
                    ibpb.Add(EXCHANGE_NAME, ROUTE_KEY, true, null, new ReadOnlyMemory<byte>(Encoding.UTF8.GetBytes(m)));
                }

                ibpb.Publish();

                // 同步确认
                //channel.WaitForConfirmsOrDie(TimeSpan.FromSeconds(3));

            }

            return Ok(new Result
            {
                Success = true,
                Msg = $"已发送消息 {msg}"
            });
        }

        private const string DELAY_EXCHANGE_NAME = "test_delay_exchange";

        /// <summary>
        /// 发送到消息队列（发送到延迟交换机）
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult RabbitMQPublishDelay(string msg = "MY_EMPTY")
        {
            msg = msg + " - "  + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

            var factory = RabbitMQService.ConnectionFactory;
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                // 声明延迟交换机的类型（与默认的交换机类型相同）
                Dictionary<string, object> exchangeParamsDic = new Dictionary<string, object>
                {
                    { "x-delayed-type", "direct" }
                };
                // 声明延迟交换机（如果没有则自动创建）
                channel.ExchangeDeclare(DELAY_EXCHANGE_NAME, "x-delayed-message", true, false, exchangeParamsDic);

                byte[] body = Encoding.UTF8.GetBytes(msg);
                IDictionary<string, object> propertyHeaderDic = new Dictionary<string, object>()
                {
                    { "x-delay", 5000 }
                };
                IBasicProperties basicProperties = channel.CreateBasicProperties();
                basicProperties.Headers = propertyHeaderDic;

                // 使用延迟队列插件时，mandatory 参数无效
                channel.BasicPublish(DELAY_EXCHANGE_NAME, "", false, basicProperties, body);
            }

            return Ok(new Result
            {
                Success = true,
                Msg = $"已发送消息 {msg}"
            });
        }
    }
}
